package gipfProject.games.zertz.engine;

import gipfProject.games.zertz.data.Location;
import gipfProject.games.zertz.data.RuleData;
import gipfProject.games.zertz.data.ZertzData;

public class ZertzEngine {
	ZertzData gameState;

	/**
	 * Creates a Zertz Engine to handle movement inputs
	 * @param gameState
	 */
	public ZertzEngine(ZertzData gameState) {
		this.gameState = gameState;
	}

	/**
	 * Begins a new game
	 */
	public void newGame(){
		gameState.newGame();
	}
	
	/**
	 * This processes a UI click on a specific location
	 * Will determine what sort of move to attempt based on moveType
	 * @param col
	 * @param row
	 */
	public void clickTile(int col, int row) {
		boolean success = false;

		//Exit prematurely if the game has already ended
		if (gameState.isGameRunning() == false){
			gameState.setErrorMessage("The game has ended");
			return;
		}
		
		Location moveLocation = new Location (col,row);
		
		//Handles the logic for captures/selects
		if (gameState.moveType == ZertzData.captureMarble){
			if (gameState.getSelectedPiece() != null){
				//Check if we have clicked the same place twice
				if (moveLocation.x == gameState.getSelectedPiece().x &&
					moveLocation.y == gameState.getSelectedPiece().y)
				{
					//If so, clear the selection
					gameState.clearSelectedPiece();
				}
				else{
					//Otherwise see if we can capture at that location
					success = tryCaptureMarble(gameState.getSelectedPiece(), moveLocation);
				}
			}
			else
			{
				//This uses the tryMove model but does NOT return a success tag
				trySelectPiece(col,row);
				
				//This is to ensure the moveType remains capturing
				success = false;
			}
		}
		
		//Handles the logic for placing marbles
		else if (gameState.moveType == ZertzData.placeMarble) {
			success = tryPlaceMarble(col, row);
		}
		
		//Handles the logic for removing rings
		else if (gameState.moveType == ZertzData.removeRing) {
			success = tryRemoveRing(col, row);
		}
		
		//Handles failure states
		else {
			success = false;
			System.out.println("ERROR from ZertzEngine.clickTile(): invalid moveType");
		}
		

		//If the move was successful, then finish this move
		if (success) {
			gameState.endMove();
		}
	}

	/**
	 * Attempts to place a marble at the specified location
	 * 
     * @param col - the location we are operating on
     * @param row - the location we are operating on
	 * @return true if successful, false if an error prevents this move
	 */
	private boolean tryPlaceMarble(int col, int row) {
		RuleData rules = new RuleData(gameState);
		
		if (rules.canPlaceMarble(col, row)) {
			gameState.placeMarble(col, row);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Attempts to remove a ring at the specified location
	 * 
     * @param col - the location we are operating on
     * @param row - the location we are operating on
	 * @return true if successful, false if an error prevents this move
	 */
	private boolean tryRemoveRing(int col, int row) {
		RuleData rules = new RuleData(gameState);
		
		if (rules.canRemoveRing(col, row)) {
			gameState.removeRing(col, row);
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Attempts to capture a marble
	 * 
     * @param startLocation - the marble that is doing the capture
     * @param endLocation   - the (empty) space that the marble is moving to
	 * @return true if successful, false if an error prevents this move
	 */
	private boolean tryCaptureMarble(Location startLocation, Location endLocation){
		RuleData rules = new RuleData(gameState);
		
		int startCol = startLocation.x;
		int startRow = startLocation.y;
		int endCol   = endLocation.x;
		int endRow   = endLocation.y;
		
		if (rules.canCapture(startCol, startRow, endCol, endRow)) {
			gameState.captureMarble(startCol, startRow, endCol, endRow);
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Attempts to select a piece for later movement in a capture
	 * 
     * @param col - the location we are operating on
     * @param row - the location we are operating on
	 * @return true if successful, false if an error prevents this move
	 */
	private boolean trySelectPiece(int col, int row){
		RuleData rules = new RuleData(gameState);
		
		if (rules.canSelect(col,row)) {
			gameState.selectPiece(col,row);
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Causes the current player to resign (be defeated)
	 */
	public void resign(){
		gameState.resign();
	}
}
